package com.sunfeng.jksj.p20;

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;

/**
 * CopyOnWriteArrayList 内部维护了一个数组，成员变量 array 就指向这个内部数组，
 * 所有的读操作都是基于 array 进行的，迭代器 Iterator 遍历的就是 array 数组。
 * <p>
 * 如果在遍历 array 的同时，还有一个写操作，例如增加元素，CopyOnWriteArrayList 是如何处理的呢？
 * CopyOnWriteArrayList 会将 array 复制一份，然后在新复制处理的数组上执行增加元素的操作，执行完之后再将 array 指向这个新的数组。
 * <p>
 * 使用 CopyOnWriteArrayList 需要注意的“坑”主要有两个方面
 * 1、一个是应用场景，CopyOnWriteArrayList 仅适用于写操作非常少的场景，而且能够容忍读写的短暂不一致。
 * 2、CopyOnWriteArrayList 迭代器是只读的，不支持增删改。因为迭代器遍历的仅仅是一个快照，而对快照进行增删改是没有意义的。
 *
 * @author sunfeng
 * @date 2021/06/09 16:15
 **/
public class TestCopyOnWriteArrayList {
    public static void main(String[] args) {

        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 1000; i++) {
            list.add("A" + i);
        }
        Thread thread1 = new Thread(() -> {
            Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()) {
                System.out.println(iterator.next()+"thread1");
                try {
                    TimeUnit.MILLISECONDS.sleep(1L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });


        thread1.start();
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 200; i++) {
                list.add("B" + i);
                try {
                    TimeUnit.MILLISECONDS.sleep(1L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        thread2.start();


        try {
            TimeUnit.MILLISECONDS.sleep(100L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        Iterator<String> iterator = list.iterator();

        while (iterator.hasNext()){
            System.out.println(iterator.next()+"main");
        }

    }
}
